home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 July: Mac OS SDK / Dev.CD Jul 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / USBSampleStorageDriver / StorageClassDriver / StorageClassShim.c < prev    next >
Encoding:
Text File  |  2000-04-25  |  25.8 KB  |  803 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        StorageClassShim.c
  3.  
  4.     Contains:    USB Storage Class Shim
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-2000 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // Universal Headers
  12.  
  13. #include <Devices.h>
  14. #include <DriverGestalt.h>
  15. #include <DriverServices.h>
  16. #include <Folders.h>
  17. #include <MacTypes.h>
  18. #include <Resources.h>
  19. #include <USB.h>
  20.  
  21. // Project Headers
  22. #include "StorageClassShim.h"
  23. #include "StorageClassPublicAPI.h"
  24. #include "StorageClassShimDS.h"
  25. #include "StorageDeviceConfiguration.h"
  26.  
  27. // Enumerations for the range of Unittable entries
  28. // in which InstallDriverFromMemory will try to install the driver
  29. enum
  30. {
  31.     kUnitTableFloppyRefNum                = 4,
  32.     kUnitTableEntryStart                = 48,
  33.     kUnitTableDriverResource             = 128
  34. };
  35.  
  36.  
  37. // These are all variables that are global to the Shim
  38. static Boolean                     shimInFile;
  39. static FSSpec                    shimFSSpec;
  40. static UInt32                    gNotificationTokenCount = 0;
  41. static UInt32                    gNotificationToken[10] = {0,0,0,0,0,0,0,0,0,0};
  42. static IOCompletionUPP            gInitCompletionUPP = nil;
  43. static IOCompletionUPP            gDeviceInfoCompletionUPP = nil;
  44. static IOCompletionUPP            gTerminateCompletionUPP = nil;
  45.  
  46. // Here are all the prototypes for functions static to the shim
  47. static UInt32         MyUSBGetVersion(void);
  48. static void            myNotificationCallback (USBDeviceNotificationParameterBlock *pb);
  49. static void         HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
  50. static void         HandleRemoveNotification( USBDeviceRef theDevRef, Boolean isDeviceNotification );
  51.  
  52. // Functions used by the shim to Install and Remove USB Expert notifications
  53. static Boolean         InstallUSBNotifications( void );
  54. static Boolean         RemoveUSBNotifications( void );
  55.  
  56. static OSStatus     ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
  57. static OSStatus     ShimCloseDriver(USBDeviceRef theDevRef);
  58.  
  59. // Internal Completion routines that have UPPs allocated.
  60. static void         InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock );
  61. static void             GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock );
  62. static void         RetryUnitTableConfig( USBPB *usbPB);
  63. static void         TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock );
  64.  
  65. // Supporting functions
  66. static OSStatus     GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef    *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification );
  67.  
  68. #pragma mark --
  69. #pragma mark Code Fragment Manager Functions
  70. /******************************** Code Fragment Manager Functions ******************************************/
  71.  
  72. // This is the Code Fragment Initialize routine.  This is called by the Code Fragment Manager when
  73. // the code fragment containing the shim is loaded.  We use this function to save the the FSSpec 
  74. // for the file containing the shim and the Unit Table Driver.
  75. OSErr CFragInitRoutine(CFragInitBlockPtr initBlkPtr)
  76. {
  77.     shimInFile = false;
  78.     
  79.     if (CFragHasFileLocation(initBlkPtr->fragLocator.where))
  80.     {
  81.         shimInFile = true;
  82.         shimFSSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec);            // save the FSSpec, in case we need it later
  83.     }
  84.     
  85.     return noErr;
  86. }
  87.  
  88. // This is the Code Fragment Terminate routine.  This is called by the Code Fragment Manager when
  89. // the code fragment containing the shim is being removed. 
  90. void CFragTermRoutine( void )
  91. {
  92.     RemoveUSBNotifications();
  93.     TerminateStorageDriverServices();
  94.     
  95.     // Free resources used by our UPPs.  Check to see if the are nil, if so no need to dispose.
  96.     if ( gInitCompletionUPP != nil )
  97.     {
  98.         DisposeRoutineDescriptor( gInitCompletionUPP );
  99.     }
  100.     
  101.     if ( gDeviceInfoCompletionUPP != nil )
  102.     {
  103.         DisposeRoutineDescriptor( gDeviceInfoCompletionUPP );
  104.     }
  105.     
  106.     if ( gTerminateCompletionUPP != nil )
  107.     {
  108.         DisposeRoutineDescriptor( gTerminateCompletionUPP );
  109.     }
  110. }
  111.  
  112. #pragma mark --
  113. #pragma mark USB Manager/Expert Functions
  114. /******************************** USB Manager/Expert Functions ******************************************/
  115. UInt32 MyUSBGetVersion(void)
  116. {
  117.     UInt32    version;
  118.     
  119.        if ((Ptr) USBGetVersion != (Ptr) kUnresolvedCFragSymbolAddress)
  120.               version = USBGetVersion();
  121.        else
  122.               version = 0;    // version of USB is less than 1.3
  123.        return version;
  124. }
  125.  
  126. // This is the initialize entry point to the shim.  This function is exported so that it can
  127. // be called when the shim is loaded.
  128. OSStatus USBShim( void )
  129. {
  130.     if ( MyUSBGetVersion() < kMinimumUSBMgrVersion )    
  131.     {
  132.         // This does not meet the minimum USB Manager version, leave now.
  133.         return noErr; // Is there an error that should be returned? Does the USB Expert check?
  134.     }
  135.  
  136.     gInitCompletionUPP = NewIOCompletionProc(InitializeCntrlCallCompletionProc);
  137.     gDeviceInfoCompletionUPP = NewIOCompletionProc(GetDeviceInfoCallCompletionProc);
  138.     gTerminateCompletionUPP = NewIOCompletionProc(TerminateCntrlCallCompletionProc);
  139.     
  140.     // The USB Manager looks to be the one we want, or can use, prepare for usage.
  141.     InitializeStorageDriverServices();
  142.     
  143.     // Install notifications last because we could get notified immediately
  144.     InstallUSBNotifications();
  145.     return noErr;
  146. }
  147.  
  148. #pragma mark --
  149. #pragma mark USB Notification Functions
  150. /******************************** USB Notification Functions ******************************************/
  151. // This is the notification routine that the Expert will call when a Mass Storage Device
  152. // has been attached to the USB or removed from the USB.
  153. void myNotificationCallback(USBDeviceNotificationParameterBlock *pb)
  154. {
  155.     Boolean isADeviceNotification = false;
  156.     
  157.     switch(pb->usbDeviceNotification)        // why were we notified?
  158.     {
  159.         case kNotifyAddDevice:                // because mass storage device appeared
  160.             isADeviceNotification = true;    // Set flag saying this is a device notification
  161.                                             // and then pass through to next case
  162.         case kNotifyAddInterface:            // because mass storage interface appeared
  163.         {    
  164.             HandleAddNotification(pb->usbDeviceRef, pb->usbVendor, pb->usbProduct, pb->usbSubClass, isADeviceNotification); 
  165.         }
  166.         break;
  167.             
  168.         case kNotifyRemoveDevice:            // because a mass storage device or interface disappeared
  169.             isADeviceNotification = true;    // Set flag saying this is a device notification
  170.                                             // and then pass through to next case
  171.         case kNotifyRemoveInterface:        // because a mass storage device or interface disappeared
  172.         {
  173.             HandleRemoveNotification( pb->usbDeviceRef, isADeviceNotification );
  174.         }
  175.         break;
  176.             
  177.         default:
  178.         {
  179.         }
  180.         break;
  181.     }
  182. }
  183.  
  184. void HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification )
  185. {
  186.     ShimOpenDriver(theDevRef, usbVendor, usbProduct, usbSubClass, isDeviceNotification); 
  187. }
  188.  
  189. void HandleRemoveNotification( USBDeviceRef theDevRef,  Boolean isDeviceNotification )
  190. {
  191. #pragma unused ( isDeviceNotification )
  192.     ShimCloseDriver( theDevRef );
  193. }
  194.  
  195. // This routine is used by the shim to install its USB notification procs
  196. Boolean InstallUSBNotifications( void )
  197. {
  198.     USBDeviceNotificationParameterBlock pb;
  199.  
  200.     // Setup notification for Mass Storage Class Devices
  201.     pb.usbDeviceNotification     = kNotifyAnyEvent;        // tell me about everything
  202.     pb.usbClass                 = kDriverClassID;        // tell me about the specified class
  203.     pb.usbSubClass                 = kDriverSubclassID;    // tell me about the specified subclass
  204.     pb.usbProtocol                 = kUSBAnyProtocol;        // tell me about all protocols for this vendor/product
  205.     pb.usbVendor                 = kDriverVendorID;        // Only notify me for this specific vendor
  206.     pb.usbProduct                 = kDriverProductID;        // and for this specific product
  207.     pb.result                     = noErr;
  208.     pb.callback                 = (USBDeviceNotificationCallbackProcPtr) &myNotificationCallback;        
  209.     pb.refcon                     = nil;
  210.      USBInstallDeviceNotification (&pb);    
  211.     if ( pb.result == noErr )
  212.     {
  213.         gNotificationToken[gNotificationTokenCount] = pb.token;
  214.         gNotificationTokenCount++;     // Zero based array,increment to get true count
  215.     }
  216.  
  217.     return true;
  218. }
  219.  
  220. // This routine is used by the shim to remove its USB notification procs
  221. Boolean RemoveUSBNotifications( void )
  222. {
  223.     while ( gNotificationTokenCount > 0 )
  224.     {
  225.         gNotificationTokenCount--;     // Zero based array, decrement the counter first
  226.         if ( gNotificationToken[gNotificationTokenCount] !=0 )
  227.         {
  228.             USBRemoveDeviceNotification( gNotificationToken[gNotificationTokenCount] );
  229.             gNotificationToken[gNotificationTokenCount]  = 0;
  230.         }
  231.     }
  232.  
  233.     return true;
  234. }
  235.  
  236. #pragma mark -- 
  237. #pragma mark Open Driver Functions
  238. static OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr);
  239. static void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr);
  240.  
  241. // This function is called by our notification routine to load a Unit Table driver when the device
  242. // we specified in our notification setup is attached
  243. OSStatus ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass,  Boolean isDeviceNotification )
  244. {
  245.     OSStatus            theErr = noErr;
  246.     Handle                hDrvrResource;
  247.     THz                    currentZone;
  248.     DriverRefNum        drvrRefNum;
  249.     void                *pTheStorageClassDispatchTable;
  250.     CFragSymbolClass    symClass;
  251.     CFragConnectionID    connID;
  252.     DriverInfoPtr        currentDriveInfoPtr;
  253.     RegEntryID             usbRegEntryID;
  254.     RegEntryIDPtr         usbRegEntryIDPtr;
  255.  
  256.     // We have been notified of a new device, check to see if we already 
  257.     // have installed a driver the USB Device Ref.
  258.     currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
  259.     if ( currentDriveInfoPtr != nil )
  260.     {
  261.         // We already have a driver loaded for this device, return
  262.         return noErr;
  263.     }
  264.  
  265.     // Check if we have a driver for the subclass installed without the device
  266.     currentDriveInfoPtr = GetDriverInfoHeadPtr();
  267.     while ( currentDriveInfoPtr != nil )
  268.     {
  269.         if(( currentDriveInfoPtr->usbDeviceRef == 0 ) && (currentDriveInfoPtr->usbSubClass == usbSubClass )
  270.             && (currentDriveInfoPtr->usbVendor == usbVendor ) && (currentDriveInfoPtr->usbProduct == usbProduct ))
  271.         {
  272.             // We have found a driver candidate
  273.             drvrRefNum = currentDriveInfoPtr->drvrRefNum;
  274.             currentDriveInfoPtr->usbDeviceRef = theDevRef;
  275.             break;
  276.         }
  277.         
  278.         currentDriveInfoPtr = currentDriveInfoPtr->nextDriverInfo;
  279.     }
  280.  
  281.     // if the currentDriveInfoPtr is nil, we know that we don't have a DriveInfo element
  282.     // for this new device yet, let's build one
  283.     if ( currentDriveInfoPtr == nil )
  284.     {
  285.         short    oldResFileID = 0;
  286.  
  287.         SetResLoad(true);
  288.         oldResFileID = CurResFile();                                    // get the current resource file ID
  289.  
  290.         // No driver has been loaded for this USBDeviceRef, find the driver's 'ndrv' resource        
  291.         if (shimInFile)
  292.         {
  293.             short    myResFileID = 0;
  294.  
  295.             myResFileID = OpenShimResourceFork();
  296.             UseResFile(myResFileID);                                        // point at the shim file
  297.  
  298.             currentZone = GetZone ();
  299.             SetZone ( SystemZone() );
  300.             hDrvrResource = Get1Resource('ndrv', kUnitTableDriverResource);    // read in the driver from a ndrv resource
  301.             DetachResource(hDrvrResource);                                    // Detach the resource so it hangs around in the system heap
  302.             SetZone (currentZone);
  303.     
  304.             UseResFile(oldResFileID);                                        // point at the original file
  305.             CloseShimResourceFork();                                        // Make sure the resource file is closed
  306.         }
  307.  
  308.         // We have found the driver's 'ndrv' resource, install it into the UnitTable
  309.         if (hDrvrResource)
  310.         {
  311.             long                drvrSize;
  312.             Ptr                    pDrvrInMemory;
  313.             USBDeviceRef        parentsDeviceRef;
  314.     
  315.             // Lock the Driver Resource in memory
  316.             HLock(hDrvrResource);
  317.     
  318.             // Get the resource information needed to install the Driver
  319.             pDrvrInMemory = *hDrvrResource;
  320.             drvrSize = GetHandleSize(hDrvrResource);
  321.  
  322.             usbRegEntryIDPtr = &usbRegEntryID;
  323.             theErr = GetRegEntryIDForUSBReference( theDevRef, &parentsDeviceRef, usbRegEntryIDPtr, isDeviceNotification );
  324.             if ( theErr != noErr )
  325.             {
  326.                 usbRegEntryIDPtr = nil;
  327.             }
  328.             
  329.             // Check if this is a floppy subclass device
  330.             if( usbSubClass == kUSBStorageUFISubclass )
  331.             {
  332.                 // If a floppy subclass, try the traditional floppy UnitTable spot first
  333.                 theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableFloppyRefNum, kUnitTableFloppyRefNum, &drvrRefNum);
  334.                 if ( theErr != noErr )
  335.                 {
  336.                     // We couldn't get the traditional spot, try normal range
  337.                     // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
  338.                     // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
  339.                     theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
  340.                 }
  341.             }
  342.             else
  343.             {
  344.                 // Install the driver
  345.                 // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
  346.                 // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
  347.                 theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
  348.             }
  349.             
  350.             if ( theErr != noErr )
  351.             {
  352.                 // The driver could not be loaded, the shim will return the error and abort the driver load
  353.                 return theErr;
  354.             }
  355.             
  356.             // Save the Driver refnum to remove the driver when the remove notification is recieved
  357.             currentDriveInfoPtr = AddDriverInfoPtr();
  358.             if (currentDriveInfoPtr == nil )
  359.             {
  360.                 // We couldn't get any memory, just bail for now.
  361.                 // Should probably figure a graceful way to handle this.
  362.                 return memFullErr;
  363.             }
  364.             
  365.             currentDriveInfoPtr->usbDeviceRef = theDevRef;
  366.             currentDriveInfoPtr->parentsDeviceRef = parentsDeviceRef;
  367.             currentDriveInfoPtr->usbSubClass = usbSubClass;
  368.             currentDriveInfoPtr->usbVendor = usbVendor;
  369.             currentDriveInfoPtr->usbProduct = usbProduct;
  370.             currentDriveInfoPtr->drvrRefNum = drvrRefNum;
  371.             currentDriveInfoPtr->drvrHndlInMemory = hDrvrResource;
  372.         }
  373.     }
  374.  
  375.     // Get the Storage class dispatch table 
  376.     currentZone = GetZone ();
  377.     SetZone ( SystemZone() );
  378.     
  379.     theErr = FindSymbol(connID, "\pTheStorageClassDispatchTable", (Ptr *)&pTheStorageClassDispatchTable, &symClass);
  380.     SetZone (currentZone);
  381.  
  382.     // If no error occured, pass the dispatch table pointer to the Driver
  383.     if (theErr == noErr)            
  384.     {
  385.         currentDriveInfoPtr->theSetupTable.usbDeviceRef = theDevRef;
  386.         currentDriveInfoPtr->theSetupTable.usbParentRef = currentDriveInfoPtr->parentsDeviceRef;
  387.         currentDriveInfoPtr->theSetupTable.usbSubClass = usbSubClass;
  388.         currentDriveInfoPtr->theSetupTable.usbVendor = usbVendor;
  389.         currentDriveInfoPtr->theSetupTable.usbProduct = usbProduct;
  390.         currentDriveInfoPtr->theSetupTable.shimDispatchTable = GetShimDispatchTablePtr();
  391.         currentDriveInfoPtr->theSetupTable.theStorageClassDispatchTable = pTheStorageClassDispatchTable;
  392.  
  393.  
  394.         theErr = SendInitializeControlCall ( currentDriveInfoPtr );
  395.     }
  396.     else
  397.     {
  398.         // We will get to this point if there was an error on either the FindSymbol call
  399.         // if an error occurs, we should remove the driver from the unittable
  400.         ShimCloseDriver(theDevRef);
  401.     }
  402.  
  403.     return theErr;
  404. }
  405.  
  406. OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr)
  407. {
  408.     OSStatus                         theErr;
  409.     USBStorageClassSetupTablePtr     theSetupTable;
  410.  
  411.     theSetupTable = ¤tDriveInfoPtr->theSetupTable;
  412.  
  413.     // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
  414.     BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
  415.     currentDriveInfoPtr->controlPB.ioCompletion = gInitCompletionUPP;
  416.     currentDriveInfoPtr->controlPB.ioVRefNum    = 0;
  417.     currentDriveInfoPtr->controlPB.ioCRefNum     = currentDriveInfoPtr->drvrRefNum;
  418.     currentDriveInfoPtr->controlPB.csCode         = kInitializeDeviceAccess;
  419.     *((UInt32 *) ¤tDriveInfoPtr->controlPB.csParam[0]) = (UInt32) theSetupTable;
  420.     theErr = PBControlAsync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  421.     if ( theErr != noErr )
  422.     {
  423.         // An error occurred on the kInitializeDeviceAccess control 
  424.         // call and it couldn't be sent, there is nothing more that 
  425.         // can be done, so remove this driver from the UnitTable
  426.         ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
  427.     }
  428.     
  429.     return theErr;
  430. }
  431.  
  432. void InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock )
  433. {
  434.     CntrlParam        *ourCntrlPB;
  435.     DriverInfoPtr     currentDriveInfoPtr;
  436.     OSStatus        theErr;
  437.  
  438.     ourCntrlPB = (CntrlParam *) paramBlock;
  439.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
  440.     theErr = currentDriveInfoPtr->controlPB.ioResult;
  441.     if ( theErr == noErr )
  442.     {
  443.         if ( currentDriveInfoPtr->hasDialog == true )
  444.         {
  445.             RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
  446.         }
  447.  
  448.         SendGetDeviceInfoDriverGestaltCall ( currentDriveInfoPtr );
  449.     }
  450.     else if ( theErr == kClassNotConfiguredError )
  451.     {
  452.         BlockZero( ¤tDriveInfoPtr->configAgainPB, sizeof(USBPB));
  453.         
  454.         currentDriveInfoPtr->configAgainPB.pbLength = sizeof(USBPB);
  455.         currentDriveInfoPtr->configAgainPB.pbVersion = kUSBCurrentPBVersion;
  456.         currentDriveInfoPtr->configAgainPB.usbCompletion = &RetryUnitTableConfig;
  457.         currentDriveInfoPtr->configAgainPB.usbRefcon = (UInt32) currentDriveInfoPtr;
  458.         currentDriveInfoPtr->configAgainPB.usbReference = currentDriveInfoPtr->usbDeviceRef;
  459.         currentDriveInfoPtr->configAgainPB.usbReqCount = 100;
  460.         currentDriveInfoPtr->configAgainPB.usbFlags = kUSBTaskTimeFlag;
  461.         
  462.         theErr = USBDelay( ¤tDriveInfoPtr->configAgainPB );
  463.         if( theErr == kUSBPending )
  464.         {
  465.             theErr = noErr;
  466.         }
  467.     }
  468.     
  469.     if ( theErr != noErr )
  470.     {
  471.         // An error occurred on either kInitializeDeviceAccess control call
  472.         // or on the USBDelay call.  In either case, there is nothing that 
  473.         // can be done, so remove this driver from the UnitTable
  474.         ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
  475.     }
  476. }
  477.  
  478. void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr)
  479. {
  480.     // Get the Vendor Name of the device from the UnitTable driver
  481.     DriverGestaltParam            *theDGPB;
  482.     OSStatus                    theErr;
  483.     
  484.     theDGPB = (DriverGestaltParam *) ¤tDriveInfoPtr->controlPB;
  485.     
  486.     BlockZero(theDGPB, sizeof(DriverGestaltParam));
  487.     
  488.     theDGPB->ioCompletion     = (ProcPtr) gDeviceInfoCompletionUPP;
  489.     theDGPB->ioCRefNum         = currentDriveInfoPtr->drvrRefNum;
  490.     theDGPB->csCode         = kDriverGestaltCode;
  491.     theDGPB->driverGestaltSelector = kdgDeviceModelInfo;
  492.     theErr = PBStatusAsync((ParamBlockRec *) theDGPB);
  493.     if ( theErr != noErr )
  494.     {
  495.         // An error an we we not able to get the Device info data
  496.         // We must use the default data instead.
  497.         PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
  498.     }
  499. }
  500.     
  501. void GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock )
  502. {
  503.     DriverGestaltParam                        *theDGPB;
  504.     DriverInfoPtr                             currentDriveInfoPtr;
  505.     OSStatus                                theErr;
  506.     DriverGestaltDeviceModelInfoResponse    *theDeviceInfo;
  507.  
  508.     theDGPB = (DriverGestaltParam *) paramBlock;
  509.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( theDGPB->ioCRefNum );
  510.     theErr = theDGPB->ioResult;
  511.     if( theErr == noErr )
  512.     {
  513.         theDeviceInfo = *(GetDriverGestaltDeviceModelInfoResponse(theDGPB));
  514.     }
  515.     else
  516.     {
  517.         theDeviceInfo = nil;
  518.     }
  519.     
  520.     if( (theDeviceInfo != nil) && ( theDeviceInfo->vendorName != nil ))
  521.     {
  522.         PStrCopy(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->vendorName);
  523.         if( theDeviceInfo->productName != nil )
  524.         {
  525.             PStrCat(currentDriveInfoPtr->VendorProductStr,"\p ");
  526.             PStrCat(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->productName);
  527.         }
  528.     }
  529.     else
  530.     {
  531.         BlockZero(theDGPB, sizeof(DriverGestaltParam));
  532.         
  533.         theDGPB->ioCRefNum = currentDriveInfoPtr->drvrRefNum;
  534.         theDGPB->csCode = kDriverGestaltCode;
  535.         theDGPB->driverGestaltSelector = kdgDeviceType;
  536.         theErr = PBStatusSync((ParamBlockRec *) theDGPB);
  537.         switch (GetDriverGestaltDevTResponse(theDGPB)->deviceType )
  538.         {
  539.             case kdgTapeType:
  540.             {
  541.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Tape Drive");
  542.             }
  543.             break;
  544.             
  545.             case kdgProcessorType:
  546.             {
  547.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Processor Device");
  548.             }
  549.             break;
  550.             
  551.             case kdgWormType:
  552.             {
  553.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown WORM Drive");
  554.             }
  555.             break;
  556.             
  557.             case kdgCDType:
  558.             {
  559.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown CD-ROM Drive");
  560.             }
  561.             break;
  562.             
  563.             case kdgFloppyType:
  564.             {
  565.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Floppy Disk Drive");
  566.             }
  567.             break;
  568.             
  569.             case kdgRemovableType:
  570.             {
  571.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Removable Media Drive");
  572.             }
  573.             break;
  574.             
  575.             case kdgDiskType:
  576.             {
  577.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Hard Disk Drive");
  578.             }
  579.             break;
  580.             
  581.             default:
  582.             {
  583.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
  584.             }
  585.         }
  586.     }
  587. }
  588.  
  589. void RetryUnitTableConfig( USBPB *usbPB)
  590. {
  591.     DriverInfoPtr                    currentDriveInfoPtr;
  592.     OSStatus                        theErr;
  593.  
  594.     currentDriveInfoPtr = (DriverInfoPtr) usbPB->usbRefcon;
  595.  
  596.     theErr = SendInitializeControlCall ( currentDriveInfoPtr );
  597. }
  598.  
  599.  
  600. #pragma mark -- 
  601. #pragma mark Close Driver Functions
  602. static OSStatus SendTerminateControlCall (DriverInfoPtr currentDriveInfoPtr);
  603.  
  604. OSStatus ShimCloseDriver(USBDeviceRef theDevRef)
  605. {
  606.     OSStatus            theErr = noErr;
  607.     DriverInfoPtr        currentDriveInfoPtr;
  608.  
  609.     currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
  610.     if ( currentDriveInfoPtr == nil )
  611.     {
  612.         // There was no device with this USB Device Ref, just leave.
  613.         return noErr;
  614.     }
  615.     
  616.     if ( currentDriveInfoPtr->drvrRefNum == 0 )
  617.     {
  618.         // There was no UT driver loaded for this USB Device Ref, just leave.
  619.         return noErr;
  620.     }
  621.     
  622.     if ( currentDriveInfoPtr->hasDialog == true )
  623.     {
  624.         // This driver has a visible dialog, remove it
  625.         RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
  626.     }
  627.  
  628.     // We need to inform the UnitTable driver that it can no longer talk to the device.
  629.     // The UnitTable driver needs to allow the class driver to be removed.
  630.     theErr = SendTerminateControlCall ( currentDriveInfoPtr );
  631.  
  632.     return theErr;
  633. }
  634.  
  635. OSStatus SendTerminateControlCall ( DriverInfoPtr currentDriveInfoPtr )
  636. {
  637.     OSStatus                         theErr;
  638.  
  639.     // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
  640.     BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
  641.     currentDriveInfoPtr->controlPB.ioVRefNum    = 0;
  642.     currentDriveInfoPtr->controlPB.ioCRefNum     = currentDriveInfoPtr->drvrRefNum;
  643.     currentDriveInfoPtr->controlPB.csCode         = kTerminateDeviceAccess;
  644.  
  645.     theErr = PBControlSync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  646.     TerminateCntrlCallCompletionProc( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  647.     return noErr;
  648. }
  649.  
  650. void TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock )
  651. {
  652.     CntrlParam            *ourCntrlPB;
  653.     DriverInfoPtr         currentDriveInfoPtr;
  654.     OSStatus            theErr;
  655.     Boolean                doDriverRemoval = true;
  656.     VCBPtr                 vol;
  657.  
  658.     ourCntrlPB = (CntrlParam *) paramBlock;
  659.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
  660.     theErr = currentDriveInfoPtr->controlPB.ioResult;
  661.     if ( theErr != noErr )
  662.     {
  663.         // The terminate control call failed, is there anything that 
  664.         // can be done at this point?
  665.         // We will try to unmount all volumes just in case we can
  666.         //return;
  667.     }
  668.     
  669.     vol = (VCBPtr) (GetVCBQHdr())->qHead;
  670.     while (vol)
  671.     {
  672.         // Check to see if this volume belongs to the driver
  673.         // that is being removed
  674.         if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
  675.         {
  676.             theErr = UnmountVol( nil, vol->vcbVRefNum );
  677.             // Check if unmount volume returns a file busy err
  678.             if (theErr == fBsyErr)
  679.             {
  680.                 doDriverRemoval = false;
  681.             }
  682.         }
  683.         
  684.         vol = (VCBPtr) vol->qLink;
  685.     }
  686.     
  687.     // if Do Removal is true, remove the drivers, else if Do Removal is false,
  688.     // display the reattach dialog box.
  689.     if ( doDriverRemoval == true )
  690.     {
  691.         theErr = RemoveDriver(currentDriveInfoPtr->drvrRefNum, false);
  692.         if ( theErr == noErr )
  693.         {
  694.             // The driver was successfully closed and removed,
  695.             // free all associated resources.
  696.             HUnlock( currentDriveInfoPtr->drvrHndlInMemory );
  697.             DisposeHandle( currentDriveInfoPtr->drvrHndlInMemory );
  698.             RemoveDriverInfoPtr( currentDriveInfoPtr );
  699.         }
  700.     }
  701.     else
  702.     {
  703.         vol = (VCBPtr) (GetVCBQHdr())->qHead;
  704.         
  705.         while (vol)
  706.         {
  707.             // Check to see if this volume belongs to the driver that is being removed
  708.             if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
  709.             {
  710.                 theErr = Eject( nil, vol->vcbVRefNum);
  711.             }
  712.             
  713.             vol = (VCBPtr) vol->qLink;
  714.         }
  715.  
  716.         // The device is already gone, clear the USB ref
  717.         currentDriveInfoPtr->usbDeviceRef = 0;
  718.         DisplayNotifcationDialog(currentDriveInfoPtr->drvrRefNum, kUSBStorageEventDeviceWasRemoved);
  719.     }
  720. }
  721.  
  722.  
  723. #pragma mark -- 
  724. #pragma mark Shim Support Functions
  725. /******************************** Shim Support Functions ******************************************/
  726. // These are the routines that the Shim needs to support its operations.  These includes initialization
  727. // routines, Unit Table driver matching and loading routines and shim termination routines.
  728.  
  729. // These two functions give us a convenient way for any part of the shim to open
  730. // and close its resource fork
  731. static int resOpenCount = 0;
  732. static short resFileRef = 0;
  733.  
  734. short OpenShimResourceFork( void )
  735. {
  736.     if (shimInFile)
  737.     {
  738.         if ( resOpenCount == 0 )
  739.         {
  740.             // If we have not already opened the file, open it now
  741.             resFileRef = FSpOpenResFile(&shimFSSpec, fsRdPerm);
  742.             if ( resFileRef !=0 )
  743.             {
  744.                 resOpenCount++;
  745.             }
  746.         }
  747.     }
  748.     else
  749.     {
  750.         resFileRef = 0;
  751.     }
  752.     
  753.     return resFileRef;
  754. }
  755.  
  756. void CloseShimResourceFork( void )
  757. {
  758.     if ( ( resOpenCount !=0 ) && ( resFileRef != 0 ))
  759.     {
  760.         resOpenCount--;
  761.     }
  762.     
  763.     if (( resOpenCount == 0 ) && ( resFileRef != 0 ))
  764.     {
  765.         CloseResFile(resFileRef);
  766.         resFileRef = 0;
  767.     }
  768. }
  769.  
  770. OSStatus GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef    *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification )
  771. {
  772.     OSStatus                 err = noErr;
  773.     RegEntryIter            cookie;
  774.     Boolean                    done;
  775.     
  776.     err = RegistryEntryIDInit(regEntryIDPtr);
  777.     if (err != noErr)
  778.     {
  779.         return err;
  780.     }
  781.         
  782.     err = RegistryEntryIterateCreate(&cookie);
  783.     if (err != noErr)
  784.     {
  785.         return err;
  786.     }
  787.  
  788.     if ( isDeviceNotification == true )
  789.     {
  790.         err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "deviceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
  791.         *parentsDeviceRef = 0;
  792.     }
  793.     else
  794.     {
  795.         RegPropertyValueSize    refPropSize = sizeof(USBDeviceRef);
  796.         
  797.         err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "interfaceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
  798.         err = RegistryPropertyGet( regEntryIDPtr, "parent-deviceRef", (void *) parentsDeviceRef, &refPropSize);
  799.     }
  800.     
  801.     RegistryEntryIterateDispose(&cookie);
  802.     return err;
  803. }